#ifndef _MAN_V4L2_H_
#define _MAN_V4L2_H_

#include "stdio.h"
#include <iostream>
#include <linux/videodev2.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <cstring>
#include <sys/mman.h>

using namespace std;

#define BUFFER_COUNT 10
#define MAN_CAPTURE_MPLANE V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE
#define MAN_CAPTURE V4L2_BUF_TYPE_VIDEO_CAPTURE
#define MAN_OUTPUT V4L2_BUF_TYPE_VIDEO_OUTPUT
struct ManV4L2Cap {
	unsigned int cap;
	std::string name;
};

struct ManPlaneStart {
	void * start;
};

struct ManBuffer {
	struct ManPlaneStart* plane_start;
	struct v4l2_plane* planes_buffer;
};

static ManV4L2Cap man_videocap[] = {
	{ V4L2_CAP_VIDEO_CAPTURE        , "V4L2_CAP_VIDEO_CAPTURE"         		},  /* Is a video capture device */
	{ V4L2_CAP_VIDEO_OUTPUT         , "V4L2_CAP_VIDEO_OUTPUT"         		},  /* Is a video output device */
	{ V4L2_CAP_VIDEO_OVERLAY        , "V4L2_CAP_VIDEO_OVERLAY"        		}, /* Can do video overlay */
	{ V4L2_CAP_VBI_CAPTURE          , "V4L2_CAP_VBI_CAPTURE"          		}, /* Is a raw VBI capture device */
	{ V4L2_CAP_VBI_OUTPUT           , "V4L2_CAP_VBI_OUTPUT"           		}, /* Is a raw VBI output device */
	{ V4L2_CAP_SLICED_VBI_CAPTURE   , "V4L2_CAP_SLICED_VBI_CAPTURE"   		}, /* Is a sliced VBI capture device */
	{ V4L2_CAP_SLICED_VBI_OUTPUT    , "V4L2_CAP_SLICED_VBI_OUTPUT"    		}, /* Is a sliced VBI output device */
	{ V4L2_CAP_RDS_CAPTURE          , "V4L2_CAP_RDS_CAPTURE"          		}, /* RDS data capture */
	{ V4L2_CAP_VIDEO_OUTPUT_OVERLAY , "V4L2_CAP_VIDEO_OUTPUT_OVERLAY" 		}, /* Can do video output overlay */
	{ V4L2_CAP_HW_FREQ_SEEK         , "V4L2_CAP_HW_FREQ_SEEK"         		}, /* Can do hardware frequency seek  */
	{ V4L2_CAP_RDS_OUTPUT           , "V4L2_CAP_RDS_OUTPUT"           		}, /* Is an RDS encoder */
	{ V4L2_CAP_VIDEO_CAPTURE_MPLANE , "V4L2_CAP_VIDEO_CAPTURE_MPLANE" 		},
	{ V4L2_CAP_VIDEO_OUTPUT_MPLANE  , "V4L2_CAP_VIDEO_OUTPUT_MPLANE"  		},
	{ V4L2_CAP_VIDEO_M2M_MPLANE     , "V4L2_CAP_VIDEO_M2M_MPLANE"     		},
	{ V4L2_CAP_VIDEO_M2M            , "V4L2_CAP_VIDEO_M2M"            		},
	{ V4L2_CAP_TUNER                , "V4L2_CAP_TUNER"                		},  /* has a tuner */
	{ V4L2_CAP_AUDIO                , "V4L2_CAP_AUDIO"                		}, /* has audio support */
	{ V4L2_CAP_RADIO                , "V4L2_CAP_RADIO"                		}, /* is a radio device */
	{ V4L2_CAP_MODULATOR            , "V4L2_CAP_MODULATOR"            		}, /* has a modulator */
	{ V4L2_CAP_SDR_CAPTURE          , "V4L2_CAP_SDR_CAPTURE"          		}, /* Is a SDR capture device */
	{ V4L2_CAP_EXT_PIX_FORMAT       , "V4L2_CAP_EXT_PIX_FORMAT"       		}, /* Supports the extended pixel format */
	{ V4L2_CAP_SDR_OUTPUT           , "V4L2_CAP_SDR_OUTPUT"           		}, /* Is a SDR output device */
	{ V4L2_CAP_META_CAPTURE         , "V4L2_CAP_META_CAPTURE"         		}, /* Is a metadata capture device */
	{ V4L2_CAP_READWRITE            , "V4L2_CAP_READWRITE"            		}, /* read/write systemcalls */
	{ V4L2_CAP_ASYNCIO              , "V4L2_CAP_ASYNCIO"              		}, /* async I/O */
	{ V4L2_CAP_STREAMING            , "V4L2_CAP_STREAMING"            		}, /* streaming I/O ioctls */
	{ V4L2_CAP_META_OUTPUT          , "V4L2_CAP_META_OUTPUT"          		}, /* Is a metadata output device */
	{ V4L2_CAP_TOUCH                , "V4L2_CAP_TOUCH"                		}, /* Is a touch device */
#if 0
	{ V4L2_CAP_IO_MC                , "V4L2_CAP_IO_MC"                		},  /* Is input/output controlled by the media controller */
#endif
	{ V4L2_CAP_DEVICE_CAPS          , "V4L2_CAP_DEVICE_CAPS"          		}  /* sets device capabilities field */
};

class ManV4L2 {
public:
	ManV4L2(string name, v4l2_buf_type type = MAN_CAPTURE);
	~ManV4L2();
	void printCameraInfo();
	int init();
	int setFmt(string fmt, unsigned int width, unsigned int height);
	int setFmt();
	int getFmt();
	int putFrame(void * frame);
	int getFmtSupport();
	int streamOn();
	int streamOff();
	void * getFrame(int time = 0);
    	struct v4l2_format fmt;
private:
	struct video_buf_t {
		void *start;
		size_t length;

	};
	struct ManBuffer m_buffers[BUFFER_COUNT];
	video_buf_t m_framebuf[BUFFER_COUNT];
	int m_fd;
	int m_index;
	int m_num_planes;
	bool m_stream_on;
	string m_name;
	v4l2_buf_type m_video_buf_type;
	struct v4l2_capability m_cap;
};


#endif
